{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "import threading\n",
    "import queue\n",
    "import cProfile\n",
    "import itertools\n",
    "import numpy as np\n",
    "\n",
    "np.random.seed(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "in_queue = queue.Queue()\n",
    "out_queue = queue.Queue()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def random_number_threading():\n",
    "    while True:\n",
    "        n = in_queue.get()\n",
    "        if n == 'STOP':\n",
    "            return\n",
    "        random_numbers = np.random.rand(n)\n",
    "        out_queue.put(random_numbers)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_random_numbers(show_output, up_to):\n",
    "    thread = threading.Thread(target=random_number_threading)\n",
    "    thread.start()\n",
    "    for i in range(up_to):\n",
    "        in_queue.put(i)\n",
    "        random_nums = out_queue.get()\n",
    "        if show_output:\n",
    "            print(random_nums)\n",
    "    in_queue.put('STOP')\n",
    "    thread.join()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[]\n",
      "[0.5488135]\n",
      "[0.71518937 0.60276338]\n",
      "[0.54488318 0.4236548  0.64589411]\n",
      "[0.43758721 0.891773   0.96366276 0.38344152]\n",
      "[0.79172504 0.52889492 0.56804456 0.92559664 0.07103606]\n",
      "[0.0871293  0.0202184  0.83261985 0.77815675 0.87001215 0.97861834]\n",
      "[0.79915856 0.46147936 0.78052918 0.11827443 0.63992102 0.14335329\n",
      " 0.94466892]\n",
      "[0.52184832 0.41466194 0.26455561 0.77423369 0.45615033 0.56843395\n",
      " 0.0187898  0.6176355 ]\n",
      "[0.61209572 0.616934   0.94374808 0.6818203  0.3595079  0.43703195\n",
      " 0.6976312  0.06022547 0.66676672]\n"
     ]
    }
   ],
   "source": [
    "generate_random_numbers(True, 10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "         740058 function calls in 5.657 seconds\n",
      "\n",
      "   Ordered by: standard name\n",
      "\n",
      "   ncalls  tottime  percall  cumtime  percall filename:lineno(function)\n",
      "        1    0.092    0.092    5.657    5.657 <ipython-input-5-04f1b90debed>:1(generate_random_numbers)\n",
      "        1    0.000    0.000    5.657    5.657 <string>:1(<module>)\n",
      "        1    0.000    0.000    0.000    0.000 _weakrefset.py:38(_remove)\n",
      "        1    0.000    0.000    0.000    0.000 _weakrefset.py:81(add)\n",
      "    20001    0.104    0.000    0.314    0.000 queue.py:121(put)\n",
      "    20000    0.226    0.000    5.250    0.000 queue.py:153(get)\n",
      "    40000    0.035    0.000    0.047    0.000 queue.py:208(_qsize)\n",
      "    20001    0.014    0.000    0.021    0.000 queue.py:212(_put)\n",
      "    20000    0.015    0.000    0.021    0.000 queue.py:216(_get)\n",
      "        1    0.000    0.000    0.000    0.000 threading.py:1012(join)\n",
      "        1    0.000    0.000    0.000    0.000 threading.py:1050(_wait_for_tstate_lock)\n",
      "        2    0.000    0.000    0.000    0.000 threading.py:1116(daemon)\n",
      "        2    0.000    0.000    0.000    0.000 threading.py:1226(current_thread)\n",
      "        1    0.000    0.000    0.000    0.000 threading.py:216(__init__)\n",
      "    40002    0.026    0.000    0.042    0.000 threading.py:240(__enter__)\n",
      "    40002    0.031    0.000    0.042    0.000 threading.py:243(__exit__)\n",
      "    20001    0.013    0.000    0.017    0.000 threading.py:249(_release_save)\n",
      "    20001    0.021    0.000    0.037    0.000 threading.py:252(_acquire_restore)\n",
      "    60002    0.037    0.000    0.071    0.000 threading.py:255(_is_owned)\n",
      "    20001    0.121    0.000    4.804    0.000 threading.py:264(wait)\n",
      "    40001    0.141    0.000    0.255    0.000 threading.py:335(notify)\n",
      "        1    0.000    0.000    0.000    0.000 threading.py:499(__init__)\n",
      "        2    0.000    0.000    0.000    0.000 threading.py:507(is_set)\n",
      "        1    0.000    0.000    0.000    0.000 threading.py:534(wait)\n",
      "        1    0.000    0.000    0.000    0.000 threading.py:728(_newname)\n",
      "        1    0.000    0.000    0.000    0.000 threading.py:763(__init__)\n",
      "        1    0.000    0.000    0.001    0.001 threading.py:834(start)\n",
      "        1    0.000    0.000    0.000    0.000 threading.py:977(_stop)\n",
      "    20002    0.080    0.000    0.080    0.000 {built-in method _thread.allocate_lock}\n",
      "        2    0.000    0.000    0.000    0.000 {built-in method _thread.get_ident}\n",
      "        1    0.000    0.000    0.000    0.000 {built-in method _thread.start_new_thread}\n",
      "        1    0.000    0.000    5.657    5.657 {built-in method builtins.exec}\n",
      "    40000    0.012    0.000    0.012    0.000 {built-in method builtins.len}\n",
      "    40002    0.016    0.000    0.016    0.000 {method '__enter__' of '_thread.lock' objects}\n",
      "    40002    0.012    0.000    0.012    0.000 {method '__exit__' of '_thread.lock' objects}\n",
      "   120006    4.574    0.000    4.574    0.000 {method 'acquire' of '_thread.lock' objects}\n",
      "        1    0.000    0.000    0.000    0.000 {method 'add' of 'set' objects}\n",
      "    40002    0.011    0.000    0.011    0.000 {method 'append' of 'collections.deque' objects}\n",
      "        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}\n",
      "        2    0.000    0.000    0.000    0.000 {method 'discard' of 'set' objects}\n",
      "        1    0.000    0.000    0.000    0.000 {method 'locked' of '_thread.lock' objects}\n",
      "    20000    0.006    0.000    0.006    0.000 {method 'popleft' of 'collections.deque' objects}\n",
      "    40003    0.060    0.000    0.060    0.000 {method 'release' of '_thread.lock' objects}\n",
      "    20001    0.008    0.000    0.008    0.000 {method 'remove' of 'collections.deque' objects}\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "cProfile.run('generate_random_numbers(False, 20000)')"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
